#include "vcl_stl.h"

#include "bkbase.h"
#include "h_base.h"
#include "h_conv.h"

namespace h_base
{

#include "gbk_to_ibm1388.tab"
#include "ibm1388_to_gbk.tab"
#include "big5hk_to_ibm937.tab"
#include "ibm937_to_big5hk.tab"
#include "gbk_to_utf_32.tab"
#include "utf_32_to_gbk.tab"
#include "big5hk_to_utf_32.tab"
#include "utf_32_to_big5hk.tab"

static unsigned char ascii_ibm1388_tab[] =
{
   0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f,
   0x16, 0x05, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26,
   0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f,
   0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d,
   0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
   0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
   0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f,
   0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
   0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
   0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
   0xe7, 0xe8, 0xe9, 0xba, 0xe0, 0xbb, 0xb0, 0x6d,
   0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
   0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
   0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
   0xa7, 0xa8, 0xa9, 0xc0, 0x4f, 0xd0, 0xa1, 0x07,
   0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17,
   0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x09, 0x0a, 0x1b,
   0x30, 0x31, 0x1a, 0x33, 0x34, 0x35, 0x36, 0x08,
   0x38, 0x39, 0x3a, 0x3b, 0x04, 0x14, 0x3e, 0xff,
   0x40, 0x40, 0x4a, 0x40, 0x40, 0x40, 0x6a, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x5f, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
};

static unsigned char ibm1388_ascii_tab[] =
{
   0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F,
   0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
   0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87,
   0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,
   0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B,
   0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,
   0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
   0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,
   0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x20, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
   0x26, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x20, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC,
   0x2D, 0x2F, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x20, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
   0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
   0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
   0x68, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
   0x71, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
   0x79, 0x7A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x5E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x20, 0x5B, 0x5D, 0x20, 0x20, 0x20, 0x20,
   0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
   0x48, 0x49, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
   0x51, 0x52, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x5C, 0x20, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
   0x59, 0x5A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
   0x38, 0x39, 0x20, 0x20, 0x20, 0x20, 0x20, 0x9F
};

static unsigned char ascii_ibm937_tab[] =
{
   0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f,
   0x16, 0x05, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26,
   0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f,
   0x40, 0x5a, 0x7f, 0x7b, 0xe0, 0x6c, 0x50, 0x7d,
   0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
   0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
   0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f,
   0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
   0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
   0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
   0xe7, 0xe8, 0xe9, 0xba, 0xb2, 0xbb, 0xb0, 0x6d,
   0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
   0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
   0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
   0xa7, 0xa8, 0xa9, 0xc0, 0x4f, 0xd0, 0xa0, 0x07,
   0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17,
   0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x09, 0x0a, 0x1b,
   0x30, 0x31, 0x1a, 0x33, 0x34, 0x35, 0x36, 0x08,
   0x38, 0x39, 0x3a, 0x3b, 0x04, 0x14, 0x3e, 0xff,
   0x40, 0x40, 0x40, 0x4a, 0x40, 0x5b, 0x6a, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x5f, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
   0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
};

static unsigned char ibm937_ascii_tab[] =
{
   0x00, 0x01, 0x02, 0x03, 0x9c, 0x09, 0x86, 0x7f,
   0x97, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   0x10, 0x11, 0x12, 0x13, 0x9d, 0x85, 0x08, 0x87,
   0x18, 0x19, 0x92, 0x8f, 0x1c, 0x1d, 0x1e, 0x1f,
   0x80, 0x81, 0x82, 0x83, 0x84, 0x0a, 0x17, 0x1b,
   0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07,
   0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
   0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a,
   0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x20, 0xa3, 0x2e, 0x3c, 0x28, 0x2b, 0x7c,
   0x26, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x20, 0x21, 0xa5, 0x2a, 0x29, 0x3b, 0xac,
   0x2d, 0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x20, 0xa6, 0x2c, 0x25, 0x5f, 0x3e, 0x3f,
   0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x60, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22,
   0x20, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
   0x68, 0x69, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
   0x71, 0x72, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x7e, 0x20, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
   0x79, 0x7a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x5e, 0x20, 0x5c, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x20, 0x20, 0x5b, 0x5d, 0x20, 0x20, 0x20, 0x20,
   0x7b, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
   0x48, 0x49, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x7d, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
   0x51, 0x52, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x24, 0x20, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
   0x59, 0x5a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
   0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
   0x38, 0x39, 0x20, 0x20, 0x20, 0x20, 0x20, 0x9f
};

static unsigned char utf_8_utf_ebcdic_tab[] =
{
   0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f,
   0x16, 0x05, 0x15, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26,
   0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f,
   0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d,
   0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
   0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
   0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f,
   0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
   0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
   0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6,
   0xe7, 0xe8, 0xe9, 0xad, 0xe0, 0xbd, 0x5f, 0x6d,
   0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
   0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
   0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
   0xa7, 0xa8, 0xa9, 0xc0, 0x4f, 0xd0, 0xa1, 0x07,
   0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x06, 0x17,
   0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x09, 0x0a, 0x1b,
   0x30, 0x31, 0x1a, 0x33, 0x34, 0x35, 0x36, 0x08,
   0x38, 0x39, 0x3a, 0x3b, 0x04, 0x14, 0x3e, 0xff,
   0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
   0x49, 0x4a, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56,
   0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66,
   0x67, 0x68, 0x69, 0x6a, 0x70, 0x71, 0x72, 0x73,
   0x74, 0x75, 0x76, 0x77, 0x78, 0x80, 0x8a, 0x8b,
   0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x9a, 0x9b, 0x9c,
   0x9d, 0x9e, 0x9f, 0xa0, 0xaa, 0xab, 0xac, 0xae,
   0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
   0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbe, 0xbf,
   0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xda, 0xdb,
   0xdc, 0xdd, 0xde, 0xdf, 0xe1, 0xea, 0xeb, 0xec,
   0xed, 0xee, 0xef, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe,
};

static unsigned char utf_ebcdic_utf_8_tab[] =
{
   0x00, 0x01, 0x02, 0x03, 0x9c, 0x09, 0x86, 0x7f,
   0x97, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   0x10, 0x11, 0x12, 0x13, 0x9d, 0x0a, 0x08, 0x87,
   0x18, 0x19, 0x92, 0x8f, 0x1c, 0x1d, 0x1e, 0x1f,
   0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x17, 0x1b,
   0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07,
   0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04,
   0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a,
   0x20, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6,
   0xa7, 0xa8, 0xa9, 0x2e, 0x3c, 0x28, 0x2b, 0x7c,
   0x26, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0,
   0xb1, 0xb2, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x5e,
   0x2d, 0x2f, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
   0xb9, 0xba, 0xbb, 0x2c, 0x25, 0x5f, 0x3e, 0x3f,
   0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3,
   0xc4, 0x60, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22,
   0xc5, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
   0x68, 0x69, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,
   0xcc, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
   0x71, 0x72, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2,
   0xd3, 0x7e, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
   0x79, 0x7a, 0xd4, 0xd5, 0xd6, 0x5b, 0xd7, 0xd8,
   0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0,
   0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0x5d, 0xe6, 0xe7,
   0x7b, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
   0x48, 0x49, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed,
   0x7d, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
   0x51, 0x52, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3,
   0x5c, 0xf4, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
   0x59, 0x5a, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
   0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
   0x38, 0x39, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0x9f,
};

unsigned int ConvertChar(const HConvertInfo *Info,
   unsigned int c)
{
   int i, j, k, m;

   for ( m = -1, i = 0, j = Info->IdxSize - 1; i <= j; )
   {
      k = (i + j) / 2;
      if ( Info->Idx[k].Key == c )
      {
         m = k;
         break;
      }
      if ( Info->Idx[k].Key < c )
      {
         m = k;
         i = k + 1;
      }
      else
      {
         j = k - 1;
      }
   }

   if ( m == -1 || Info->Idx[m].Key + Info->Idx[m].Qty <= c )
   {
      return CONV_NULL;
   }
   else
   {
      if ( Info->Idx[m].Serial )
      {
         return Info->Idx[m].Start + c - Info->Idx[m].Key;
      }
      else
      {
         return Info->Tab[Info->Idx[m].Start + c - Info->Idx[m].Key];
      }
   }
}

int NameToDir(const char *Name)
{
   static const char *Names[] =
   {
      "GBK_TO_IBM1388",
      "IBM1388_TO_GBK",
      "BIG5HK_TO_IBM937",
      "IBM937_TO_BIG5HK",
      "GBK_TO_UTF_8",
      "UTF_8_TO_GBK",
      "BIG5HK_TO_UTF_8",
      "UTF_8_TO_BIG5HK",
      "UTF_8_TO_UTF_EBCDIC",
      "UTF_EBCDIC_TO_UTF_8",
      NULL
   };

   for ( int i = 0; Names[i] != NULL; i++ )
   {
      if ( strcmp(Name, Names[i]) == 0 )
      {
         return i;
      }
   }

   return -1;
}

HConvertInfo *GetConvInfo(int Dir)
{
   switch ( Dir )
   {
   case GBK_TO_IBM1388 :
      return &gbk_to_ibm1388_inf;
   case IBM1388_TO_GBK :
      return &ibm1388_to_gbk_inf;
   case BIG5HK_TO_IBM937 :
      return &big5hk_to_ibm937_inf;
   case IBM937_TO_BIG5HK :
      return &ibm937_to_big5hk_inf;
   case GBK_TO_UTF_8 :
      return &gbk_to_utf_32_inf;
   case UTF_8_TO_GBK :
      return &utf_32_to_gbk_inf;
   case BIG5HK_TO_UTF_8 :
      return &big5hk_to_utf_32_inf;
   case UTF_8_TO_BIG5HK :
      return &utf_32_to_big5hk_inf;
   case UTF_8_TO_UTF_EBCDIC :
   case UTF_EBCDIC_TO_UTF_8 :
      return NULL;
   default :
      return NULL;
   }
}

unsigned char ConvChar(unsigned char c, int Dir)
{
   switch ( Dir )
   {
   case GBK_TO_IBM1388 :
      return ascii_ibm1388_tab[c];
   case IBM1388_TO_GBK :
      return ibm1388_ascii_tab[c];
   case BIG5HK_TO_IBM937 :
      return ascii_ibm937_tab[c];
   case IBM937_TO_BIG5HK :
      return ibm937_ascii_tab[c];
   case GBK_TO_UTF_8 :
   case UTF_8_TO_GBK :
   case BIG5HK_TO_UTF_8 :
   case UTF_8_TO_BIG5HK :
      return c;
   case UTF_8_TO_UTF_EBCDIC :
      return utf_8_utf_ebcdic_tab[c];
   case UTF_EBCDIC_TO_UTF_8 :
      return utf_ebcdic_utf_8_tab[c];
   default :
      return c;
   }
}

unsigned int ConvWchar(unsigned int c, int Dir)
{
   return ConvertChar(GetConvInfo(Dir), c);
}

//   Char. number range  |        UTF-8 octet sequence
//      (hexadecimal)    |              (binary)
//   --------------------+---------------------------------------------
//   0000 0000-0000 007F | 0xxxxxxx
//   0000 0080-0000 07FF | 110xxxxx 10xxxxxx
//   0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
//   0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

static int Utf32ToUtf8(unsigned int Code, unsigned char *Buf, int MaxLen)
{
   if ( Code <= 0x7f )
   {
      if ( MaxLen >= 1 )
      {
         Buf[0] = Code;
         return 1;
      }
      else
      {
         return 0;
      }
   }

   if ( Code <= 0x7ff )
   {
      if ( MaxLen >= 2 )
      {
         Buf[0] = ( Code >> 6 ) | 0xc0;
         Buf[1] = ( Code & 0x3f ) | 0x80;
         return 2;
      }
      else
      {
         return 0;
      }
   }

   if ( Code <= 0xffff )
   {
      if ( MaxLen >= 3 )
      {
         Buf[0] = ( Code >> 12 ) | 0xe0;
         Buf[1] = ( ( Code >> 6 ) & 0x3f ) | 0x80;
         Buf[2] = ( Code & 0x3f ) | 0x80;
         return 3;
      }
      else
      {
         return 0;
      }
   }

   if ( Code <= 0x10ffff )
   {
      if ( MaxLen >= 4 )
      {
         Buf[0] = ( Code >> 18 ) | 0xf0;
         Buf[1] = ( ( Code >> 12 ) & 0x3f ) | 0x80;
         Buf[2] = ( ( Code >> 6 ) & 0x3f ) | 0x80;
         Buf[3] = ( Code & 0x3f ) | 0x80;
         return 4;
      }
      else
      {
         return 0;
      }
   }

   return 0;
}

static int Utf8ToUtf32(unsigned int &Code,
   const unsigned char *Buf, int MaxLen)
{
   int i = 0;

   if ( i + 1 > MaxLen )
   {
      Code = CONV_NULL;
      return i;
   }

   int Qty;
   unsigned char c = Buf[i++];

   if ( ( c & 0x80 ) == 0x00 )
   {
      Code = c;
      Qty = 0;
   }
   else if ( ( c & 0xe0 ) == 0xc0 )
   {
      Code = c & 0x1f;
      Qty = 1;
   }
   else if ( ( c & 0xf0 ) == 0xe0 )
   {
      Code = c & 0x0f;
      Qty = 2;
   }
   else if ( ( c & 0xf8 ) == 0xf0 )
   {
      Code = c & 0x07;
      Qty = 3;
   }
   else
   {
      Code = CONV_NULL;
      return i;
   }

   if ( i + Qty > MaxLen )
   {
      Code = CONV_NULL;
      return MaxLen;
   }

   for ( ; Qty > 0; Qty-- )
   {
      if ( ( Buf[i] & 0xc0 ) != 0x80 )
      {
         Code = CONV_NULL;
         return i;
      }
      Code = ( Code << 6 ) + ( Buf[i++] & 0x3f );
   }

   return i;
}

static int Utf32ToUtfebcdic(unsigned int Code, unsigned char *Buf, int MaxLen)
{
   if ( Code <= 0x9f )
   {
      if ( MaxLen >= 1 )
      {
         Buf[0] = utf_8_utf_ebcdic_tab[Code];
         return 1;
      }
      else
      {
         return 0;
      }
   }

   if ( Code <= 0x3ff )
   {
      if ( MaxLen >= 2 )
      {
         Buf[0] = utf_8_utf_ebcdic_tab[( Code >> 5 ) | 0xc0];
         Buf[1] = utf_8_utf_ebcdic_tab[( Code & 0x1f ) | 0xa0];
         return 2;
      }
      else
      {
         return 0;
      }
   }

   if ( Code <= 0x3fff )
   {
      if ( MaxLen >= 3 )
      {
         Buf[0] = utf_8_utf_ebcdic_tab[( Code >> 10 ) | 0xe0];
         Buf[1] = utf_8_utf_ebcdic_tab[( ( Code >> 5 ) & 0x1f ) | 0xa0];
         Buf[2] = utf_8_utf_ebcdic_tab[( Code & 0x1f ) | 0xa0];
         return 3;
      }
      else
      {
         return 0;
      }
   }

   if ( Code <= 0x3ffff )
   {
      if ( MaxLen >= 4 )
      {
         Buf[0] = utf_8_utf_ebcdic_tab[( Code >> 15 ) | 0xf0];
         Buf[1] = utf_8_utf_ebcdic_tab[( ( Code >> 10 ) & 0x1f ) | 0xa0];
         Buf[2] = utf_8_utf_ebcdic_tab[( ( Code >> 5 ) & 0x1f ) | 0xa0];
         Buf[3] = utf_8_utf_ebcdic_tab[( Code & 0x1f ) | 0xa0];
         return 4;
      }
      else
      {
         return 0;
      }
   }

   if ( Code <= 0x10ffff )
   {
      if ( MaxLen >= 5 )
      {
         Buf[0] = utf_8_utf_ebcdic_tab[( Code >> 20 ) | 0xf8];
         Buf[1] = utf_8_utf_ebcdic_tab[( ( Code >> 15 ) & 0x1f ) | 0xa0];
         Buf[2] = utf_8_utf_ebcdic_tab[( ( Code >> 10 ) & 0x1f ) | 0xa0];
         Buf[3] = utf_8_utf_ebcdic_tab[( ( Code >> 5 ) & 0x1f ) | 0xa0];
         Buf[4] = utf_8_utf_ebcdic_tab[( Code & 0x1f ) | 0xa0];
         return 5;
      }
      else
      {
         return 0;
      }
   }

   return 0;
}

static int UtfebcdicToUtf32(unsigned int &Code,
   const unsigned char *Buf, int MaxLen)
{
   int i = 0;

   if ( i + 1 > MaxLen )
   {
      Code = CONV_NULL;
      return i;
   }

   int Qty;
   unsigned char c = utf_ebcdic_utf_8_tab[Buf[i++]];

   if ( c < 0xa0 )
   {
      Code = c;
      Qty = 0;
   }
   else if ( ( c & 0xe0 ) == 0xc0 )
   {
      Code = c & 0x1f;
      Qty = 1;
   }
   else if ( ( c & 0xf0 ) == 0xe0 )
   {
      Code = c & 0x0f;
      Qty = 2;
   }
   else if ( ( c & 0xf8 ) == 0xf0 )
   {
      Code = c & 0x07;
      Qty = 3;
   }
   else if ( ( c & 0xfe ) == 0xf8 )
   {
      Code = c & 0x01;
      Qty = 4;
   }
   else
   {
      Code = CONV_NULL;
      return i;
   }

   if ( i + Qty > MaxLen )
   {
      Code = CONV_NULL;
      return MaxLen;
   }

   for ( ; Qty > 0; Qty-- )
   {
      c = utf_ebcdic_utf_8_tab[Buf[i]];
      if ( ( c & 0xe0 ) != 0xa0 )
      {
         Code = CONV_NULL;
         return i;
      }
      Code = ( Code << 5 ) + ( c & 0x1f );
      i++;
   }

   return i;
}

int ConvStr(void *ADes, const void *ASrc, int Len, int Dir)
{
   int i, j;
   unsigned char *Des = static_cast<unsigned char*>(ADes);
   const unsigned char *Src = static_cast<const unsigned char*>(ASrc);

   if ( Dir == GBK_TO_IBM1388 || Dir == BIG5HK_TO_IBM937 )
   {
      for ( i = 0, j = 0;
            ( Len == -1 && Src[i] != '\0' ) ||
            ( Len != -1 && i < Len && j < Len ); )
      {
         if ( Src[i] < 0x80 )
         {
            Des[j++] = ConvChar(Src[i++], Dir);
            continue;
         }
         if ( ( Len == -1 && Src[i + 1] == '\0' ) ||
              ( Len != -1 && ( i == Len - 1 || j > Len - 4 ) ) )
         {
            break;
         }
         Des[j++] = 0x0e;
         for ( ; ; )
         {
            if ( ( Len != -1 && j > Len - 3 ) || Src[i] < 0x80 )
            {
               break;
            }
            unsigned int t = Src[i] * 256 + Src[i + 1];
            i += 2;
            t = ConvWchar(t, Dir);
            if ( t == CONV_NULL )
            {
               Des[j++] = 0x40;
               Des[j++] = 0x40;
            }
            else
            {
               Des[j++] = t / 256;
               Des[j++] = t % 256;
            }
         }
         Des[j++] = 0x0f;
      }
      if ( Len == -1 )
      {
         Des[j] = '\0';
      }
      else
      {
         for ( ; j < Len; j++ )
         {
            Des[j] = 0x40;
         }
      }
      return j;
   }

   if( Dir == IBM1388_TO_GBK || Dir == IBM937_TO_BIG5HK )
   {
      for ( i = 0, j = 0;
            ( Len == -1 && Src[i] != '\0' ) ||
            ( Len != -1 && i < Len && j < Len ); )
      {
         if ( Src[i] != 0x0e )
         {
            Des[j++] = ConvChar(Src[i++], Dir);
            continue;
         }
         i++;
         for ( ; ; )
         {
            if ( Src[i] == 0x0f )
            {
               i++;
               break;
            }
            if ( Len == -1 && Src[i] == '\0' )
            {
               break;
            }
            if ( Len == -1 && Src[i + 1] == '\0' )
            {
               i++;
               break;
            }
            if ( Len != -1 && i > Len - 2 )
            {
               i = Len;
               break;
            }
            unsigned int t = Src[i] * 256 + Src[i + 1];
            i += 2;
            t = ConvWchar(t, Dir);
            if ( t == CONV_NULL )
            {
               Des[j++] = 0x3f;
            }
            else
            {
               Des[j++] = t / 256;
               Des[j++] = t % 256;
            }
         }
      }
      if ( Len == -1 )
      {
         Des[j] = '\0';
      }
      else
      {
         for ( ; j < Len; j++ )
         {
            Des[j] = 0x20;
         }
      }
      return j;
   }

   if( Dir == GBK_TO_UTF_8 || Dir == BIG5HK_TO_UTF_8 )
   {
      for ( i = 0, j = 0;
            ( Len == -1 && Src[i] != '\0' ) ||
            ( Len != -1 && i < Len && j < Len ); )
      {
         if ( Src[i] < 0x80 )
         {
            Des[j++] = Src[i++];
            continue;
         }
         if ( ( Len == -1 && Src[i + 1] == '\0' ) ||
              ( Len != -1 && ( i == Len - 1 || j > Len - 4 ) ) )
         {
            break;
         }
         unsigned int t = Src[i] * 256 + Src[i + 1];
         i += 2;
         t = ConvWchar(t, Dir);
         if ( t == CONV_NULL )
         {
            Des[j++] = 0x3f;
         }
         else
         {
            j += Utf32ToUtf8(t, Des + j, Len == -1 ? 4 : Len - j);
         }
      }
      if ( Len == -1 )
      {
         Des[j] = '\0';
      }
      else
      {
         for ( ; j < Len; j++ )
         {
            Des[j] = 0x20;
         }
      }
      return j;
   }

   if( Dir == UTF_8_TO_GBK || Dir == UTF_8_TO_BIG5HK )
   {
      for ( i = 0, j = 0;
            ( Len == -1 && Src[i] != '\0' ) ||
            ( Len != -1 && i < Len && j < Len ); )
      {
         if ( Src[i] < 0x80 )
         {
            Des[j++] = Src[i++];
            continue;
         }
         if ( Len != -1 && j + 2 > Len )
         {
            break;
         }
         unsigned int t;
         i += Utf8ToUtf32(t, Src + i, Len == -1 ? 4 : Len - i);
         if ( t != CONV_NULL )
         {
            t = ConvWchar(t, Dir);
         }
         if ( t == CONV_NULL )
         {
            Des[j++] = 0x3f;
         }
         else
         {
            Des[j++] = t / 256;
            Des[j++] = t % 256;
         }
      }
      if ( Len == -1 )
      {
         Des[j] = '\0';
      }
      else
      {
         for ( ; j < Len; j++ )
         {
            Des[j] = 0x20;
         }
      }
      return j;
   }

   if ( Dir == UTF_8_TO_UTF_EBCDIC )
   {
      for ( i = 0, j = 0;
            ( Len == -1 && Src[i] != '\0' ) ||
            ( Len != -1 && i < Len && j < Len ); )
      {
         unsigned int t;
         i += Utf8ToUtf32(t, Src + i, Len == -1 ? 4 : Len - i);
         if ( t == CONV_NULL )
         {
            Des[j++] = 0x40;
         }
         else
         {
            j += Utf32ToUtfebcdic(t, Des + j, Len == -1 ? 4 : Len - j);
         }
      }
      if ( Len == -1 )
      {
         Des[j] = '\0';
      }
      else
      {
         for ( ; j < Len; j++ )
         {
            Des[j] = 0x40;
         }
      }
      return j;
   }

   if ( Dir == UTF_EBCDIC_TO_UTF_8 )
   {
      for ( i = 0, j = 0;
            ( Len == -1 && Src[i] != '\0' ) ||
            ( Len != -1 && i < Len && j < Len ); )
      {
         unsigned int t;
         i += UtfebcdicToUtf32(t, Src + i, Len == -1 ? 4 : Len - i);
         if ( t == CONV_NULL )
         {
            Des[j++] = 0x3f;
         }
         else
         {
            j += Utf32ToUtf8(t, Des + j, Len == -1 ? 4 : Len - j);
         }
      }
      if ( Len == -1 )
      {
         Des[j] = '\0';
      }
      else
      {
         for ( ; j < Len; j++ )
         {
            Des[j] = 0x20;
         }
      }
      return j;
   }

   return 0;
}

int ConvStr(void *ADes, const void *ASrc, int Dir)
{
   return ConvStr(ADes, ASrc, -1, Dir);
}

void PrintConvTab(const map<unsigned int, unsigned int> &Map,
   const char *Name)
{
   typedef map<unsigned int, unsigned int>::const_iterator HMapIter;
   HMapIter i, j;
   HConvertIndex Index;
   vector<HConvertIndex> IndexVec;
   vector<unsigned int> SpecCharVec;

   for ( i = Map.begin(); i != Map.end(); )
   {
// key连续的一段称为一个block
      HMapIter BlockBegin, BlockEnd;
      BlockBegin = i;
      for ( j = i++; i != Map.end() && i->first == j->first + 1; j = i++ )
         ;
      BlockEnd = i;
// 值连续的一段称为一个sequence，sequence之外的字符称为special char
      HMapIter SpecCharBegin, SpecCharEnd;
      SpecCharBegin = BlockBegin;
      for ( i = BlockBegin; i != BlockEnd ; )
      {
         int SeqLen;
         HMapIter SeqBegin, SeqEnd;
         SeqBegin = i;
         for ( SeqLen = 1, j = i++;
               i != BlockEnd && i->second == j->second + 1;
               j = i++, SeqLen++ )
            ;
         SeqEnd = i;
         if ( SeqLen >= 8 || SeqEnd == BlockEnd )
         {
            if ( SeqLen < 8 )
            {
               SeqBegin = SeqEnd;
            }
            Index.Key = SpecCharBegin->first;
            Index.Start = SpecCharVec.size();
            Index.Qty = 0;
            Index.Serial = 0;
            for ( ;SpecCharBegin != SeqBegin; SpecCharBegin++ )
            {
               SpecCharVec.push_back(SpecCharBegin->second);
               Index.Qty++;
            }
            if ( Index.Qty > 0 )
            {
               IndexVec.push_back(Index);
            }
         }
         if ( SeqLen >= 8 )
         {
            Index.Key = SeqBegin->first;
            Index.Start = SeqBegin->second;
            Index.Qty = SeqLen;
            Index.Serial = 1;
            IndexVec.push_back(Index);
            SpecCharBegin = SeqEnd;
         }
      }
   }

   printf("static unsigned int %s_tab[] =\n", Name);
   printf("{\n");

   int ItemQty = 0;

   for ( int i = 0; i < SpecCharVec.size(); i++ )
   {
      if ( ItemQty % 8 == 0 )
      {
         printf("   ");
      }
      printf("0x%05x, ", SpecCharVec[i]);
      if ( ItemQty % 8 == 7 )
      {
         printf("\n");
      }
      ItemQty++;
   }

   if ( ItemQty % 8 != 0 )
   {
      printf("\n");
   }

   printf("};\n\n");
   printf("static struct HConvertIndex %s_idx[] =\n", Name);
   printf("{\n");

   for ( int i = 0; i < IndexVec.size(); i++ )
   {
      HConvertIndex &Index = IndexVec[i];
      if ( i % 2 == 0 )
      {
         printf("   ");
      }
      printf("{0x%05x, 0x%05x, 0x%04x, %d}, ",
         Index.Key, Index.Start, Index.Qty, Index.Serial);
      if ( i % 2 == 1 )
      {
         printf("\n");
      }
   }

   if ( IndexVec.size() % 2 == 1 )
   {
      printf("\n");
   }

   printf("};\n\n");
   printf("static struct HConvertInfo %s_inf = \n", Name);
   printf("{\n");
   printf("   %s_tab,\n", Name);
   printf("   %s_idx,\n", Name);
   printf("   sizeof(%s_idx) / sizeof(HConvertIndex)\n", Name);
   printf("};\n");
}

HCodeSet StrToCodeSet(const HString &CodeSetStr)
{
   if ( strcasecmp(CodeSetStr.c_str(), "GBK") == 0 )
   {
      return csGbk;
   }

   if ( strcasecmp(CodeSetStr.c_str(), "BIG5") == 0 )
   {
      return csBig5;
   }

   if ( strcasecmp(CodeSetStr.c_str(), "UTF8") == 0 )
   {
      return csUtf8;
   }

   return csNone;
}

HString CodeSetToStr(HCodeSet CodeSet)
{
   switch ( CodeSet )
   {
   case csGbk :
      return "GBK";
   case csBig5 :
      return "BIG5";
   case csUtf8 :
      return "UTF8";
   default :
      return "";
   }
}

void ConvString(HCodeSet From, HCodeSet To, char *Str)
{
   char TmpStr[8192 + 1];

   if ( From == To || From == csNone || To == csNone )
   {
      return;
   }

   if ( From == csUtf8 )
   {
      switch ( To )
      {
      case csGbk :
         ConvStr(TmpStr, Str, UTF_8_TO_GBK);
         break;
      case csBig5 :
         ConvStr(TmpStr, Str, UTF_8_TO_BIG5HK);
         break;
      }
      BkStrNCpy(Str, TmpStr, 8192);
      return;
   }

   if ( To == csUtf8 )
   {
      switch ( From )
      {
      case csGbk :
         ConvStr(TmpStr, Str, GBK_TO_UTF_8);
         break;
      case csBig5 :
         ConvStr(TmpStr, Str, BIG5HK_TO_UTF_8);
         break;
      }
      BkStrNCpy(Str, TmpStr, 8192);
      return;
   }

   switch ( From )
   {
   case csGbk :
      ConvStr(TmpStr, Str, GBK_TO_UTF_8);
      break;
   case csBig5 :
      ConvStr(TmpStr, Str, BIG5HK_TO_UTF_8);
      break;
   }

   switch ( To )
   {
   case csGbk :
      ConvStr(Str, TmpStr, UTF_8_TO_GBK);
      break;
   case csBig5 :
      ConvStr(Str, TmpStr, UTF_8_TO_BIG5HK);
      break;
   }
}

};
